package edu.upc.wib.service.impl;

import edu.upc.wib.dao.ReporteDao;
import edu.upc.wib.entity.Contendor;
import edu.upc.wib.entity.ReporteEfectividad;
import edu.upc.wib.entity.ReporteTorneo;
import edu.upc.wib.service.ReporteService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 *
 * @author rv
 */
@Service
public class ReporteServiceImpl implements ReporteService {

    private static Logger log = LoggerFactory.getLogger(ReporteServiceImpl.class);
    
    @Autowired
    private ReporteDao reporteDao;

    @Override
    public List<ReporteEfectividad> generarReporteEfectividad(Integer idUsuario) {
        log.info("Generando Reporte");
        return reporteDao.generarReporteEfectividad(idUsuario);
    }

    List<ReporteTorneo> lst = new ArrayList<ReporteTorneo>();
    Integer position = 1;
    Map<Integer, Map<Integer, Integer>> scoress = new HashMap<Integer, Map<Integer, Integer>>();
    Map<Integer, Map<Integer, Contendor>> ganadoress = new HashMap<Integer, Map<Integer, Contendor>>();
    
    @Override
    public List<ReporteTorneo> generarReporteTorneo(Integer idTorneo, Integer idUsuario) {
        log.info("Generando Reporte");
        
        List<ReporteTorneo> source = reporteDao.generarReporteTorneo(idTorneo, idUsuario);
        
        if (source.isEmpty()) {
            return null;
        }
        
        scoress.put(0, new HashMap<Integer, Integer>());
        scoress.put(1, new HashMap<Integer, Integer>());
        scoress.put(2, new HashMap<Integer, Integer>());
        ganadoress.put(0, new HashMap<Integer, Contendor>());
        ganadoress.put(1, new HashMap<Integer, Contendor>());
        ganadoress.put(2, new HashMap<Integer, Contendor>());

        for (int i = 0; i < source.size(); i++) {
            ReporteTorneo row = source.get(i);
            
            Contendor cx1 = row.getContendor1();
            
            if (row.getPosFixture() == 1){

                generarPuntaje(0, row);
                
                if (cx1.getAgrupadorInicial() != source.get(i + 1).getContendor1().getAgrupadorInicial()) {
                    calcularGanador(0, source, i);
                }
            }
            else{
                if (position == row.getPosFixture()) {
                    continue;
                }
                position = row.getPosFixture();
                
                //se busca los ganadores de la ronda anterior como competidores de la siguiente ronda
                for (int j = 0; j < lst.size(); j+=2) {
                    if ((j + 1) == lst.size()) { break; } 
                    
                    Integer g1 = lst.get(j).getGanador().getIdContendor();
                    Integer g2 = lst.get(j + 1).getGanador().getIdContendor();
                    
                    boolean _break = false;
                    boolean cal = false;
                    
                    for (int h = i; h < source.size(); h++) {
                        row = source.get(h);
                        
                        if (position != row.getPosFixture()) { _break = true; break; }
                        
                        cx1 = row.getContendor1();
                        Contendor cx2 = row.getContendor2();
                        
                        Boolean criterio = (cx1.getIdContendor() == g1 && cx2.getIdContendor() == g2);
                        if (criterio) { generarPuntaje(1, row); cal = true; }
                    }
                    
                    if (_break) { break; }
                    
                    if (cal){
                        row.setContendor1(lst.get(j).getGanador());
                        row.setContendor2(lst.get(j + 1).getGanador());
                        calcularGanador(1, source, i);
                    }
                }
                
                //TODO: Validar funcionamiento en elDebug
            }
        }
        
        return lst;
    }

    private void generarPuntaje(Integer scoressKey, ReporteTorneo row){
        Map<Integer, Integer> scores = scoress.get(scoressKey);
        Map<Integer, Contendor> ganadores = ganadoress.get(scoressKey);
        Integer val = 0;
        
        Contendor ganador = row.getGanador();
        Integer id = ganador.getIdContendor();

        //validar si existe ganador
        if (scores.containsKey(id)) {
            val = (Integer)scores.get(id);
        }
        else {
            ganadores.put(id, ganador);
        }

        //incrementar el puntaje del ganador
        scores.put(id, new Integer (val + 1));
    }
    
    private void calcularGanador(Integer key, List<ReporteTorneo> source, Integer i) {
        
        ReporteTorneo rpt = source.get(i);
        Map<Integer, Integer> scores = scoress.get(key);
        Map<Integer, Contendor> ganadores = ganadoress.get(key);
        Integer val = 0;
        boolean addRpt = false;
        
        Set set = scores.entrySet();
        Iterator iterator = set.iterator(); 
        while(iterator.hasNext()) { 
            Map.Entry me = (Map.Entry)iterator.next(); 
            Integer meKey = (Integer)me.getKey();
            Integer meValue = (Integer)me.getValue();
            
            //ir almacenando al ganador si su puntaje es mayor al del anterior
            if (meValue.intValue() > val.intValue())
            {
                addRpt = true;
                val = meValue;
                rpt.setGanador((Contendor)ganadores.get(meKey));    
            }
            else{
                //existe empate
                if (meValue.intValue() == val.intValue()){
                    //si key == 2 => se agrega el primer contendor encontrado.
                    if (key.intValue() != 2){
                        //ir hasta la siguiente ronda
                        
                        boolean cal = false;
                        for (int j = i; j < source.size(); j++) {
                            ReporteTorneo row = source.get(j);
                            
                            if (row.getPosFixture() != (position + 1)) { continue; }

                            //Contendor1 es ganador?
                            Boolean criterio = (rpt.getGanador().getIdContendor() == row.getGanador().getIdContendor());

                            if (criterio) { generarPuntaje(2, row); cal = true; }
                            else
                            {
                                //Contendor2 es ganador?
                                criterio = (meKey == row.getGanador().getIdContendor());
                                if (criterio) { generarPuntaje(2, row); cal = true; }
                            }
                        }
                        
                        if (cal){
                            calcularGanador(2, source, i);
                            addRpt = false;
                        }
                    }
                }
            }
        }
        
        if (addRpt){ lst.add(rpt); }
        
        //cleaning Objects
        scoress.put(key, new HashMap<Integer, Integer>());
        ganadoress.put(key, new HashMap<Integer, Contendor>());
    }
}